# -*- coding: utf-8 -*-

# Define here the models for your spider middleware
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/spider-middleware.html
import random

from scrapy import signals

from proxyips.base.base import agents

'''
这个是soider中间件
'''
class ProxyipsSpiderMiddleware(object):
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the spider middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_spider_input(self, response, spider):
        '''
        当response通过spider中间件时，该方法被调用，处理该response。
        process_spider_input() 应该返回 None 或者抛出一个异常。
        如果其返回 None ，Scrapy将会继续处理该response，调用所有其他的中间件直到spider处理该response。
        如果其跑出一个异常(exception)，Scrapy将不会调用任何其他中间件的 process_spider_input() 方法，
        并调用request的errback。 errback的输出将会以另一个方向被重新输入到中间件链中，
        使用 process_spider_output() 方法来处理，当其抛出异常时则带调用 process_spider_exception() 。
        '''
        return None

    def process_spider_output(self, response, result, spider):
        '''
        当Spider处理response返回result时，该方法被调用。
        process_spider_output() 必须返回包含 Request 、dict 或 Item 对象的可迭代对象(iterable)。
        '''
        for i in result:
            yield i

    def process_spider_exception(self, response, exception, spider):
        """
        当spider或(其他spider中间件的) process_spider_input() 跑出异常时， 该方法被调用。
        process_spider_exception() 必须要么返回 None ， 返回一个包含 Response 、dict 或 Item 对象的可迭代对象(iterable)
        如果其返回 None ，Scrapy将继续处理该异常，调用中间件链中的其他中间件的 process_spider_exception() 方法，直到所有中间件都被调用，
        该异常到达引擎(异常将被记录并被忽略)。如果其返回一个可迭代对象，则中间件链的 process_spider_output() 方法被调用， 
        其他的 process_spider_exception() 将不会被调用。
        """
        pass

    def process_start_requests(self, start_requests, spider):
        """
该方法以spider 启动的request为参数被调用，执行的过程类似于 process_spider_output() ，只不过其没有相关联的response并且必须返回request(不是item)。

其接受一个可迭代的对象(start_requests 参数)且必须返回另一个包含 Request 对象的可迭代对象。
        """
        for r in start_requests:
            yield r

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

'''
这是一个下载器中间件
'''
class processMiddleware(object):
    def process_request(self, request, spider):
        """
        对于通过下载中间件的每个请求都调用此方法。
        process_request()应该：返回None，返回一个 Response对象，返回一个Request 对象，或者加注IgnoreRequest。
        如果它返回None，Scrapy将继续处理此请求，执行所有其他中间件，直到最后，适当的下载程序处理程序被称为执行的请求（并且其响应已下载）
        如果它返回一个Response对象，Scrapy不会打扰调用任何其他process_request()或process_exception()方法或适当的下载功能; 它会返回该响应。process_response() 安装的中间件的方法总是在每个响应中调用。
        如果它返回一个Request对象，Scrapy将停止调用process_request方法并重新计划返回的请求。一旦执行了新返回的请求，将在下载的响应上调用适当的中间件链。
        如果引发IgnoreRequest异常，process_exception()将会调用安装的下载器中间件的 方法。如果没有处理异常，Request.errback则调用request（）的errback函数。如果没有代码处理引发的异常，它将被忽略并且不记录（与其他异常不同）。
        :param request: 
        :param spider: 
        :return: 
        """
        # # Use the following lines if your proxy requires authentication
        # proxy_user_pass = "USERNAME:PASSWORD"
        # # setup basic authentication for the proxy
        # encoded_user_pass = base64.encodestring(proxy_user_pass)
        # request.headers['Proxy-Authorization'] = 'Basic ' + encoded_user_pass
        print("**********process_request12***********")
        print (str(request))
        self.logger = spider.logger
        self.spidersql = spider.spidersql
        self.cursor = spider.cursor
        self.mysql = spider.mysql
        #request.headers.setdefault("User-Agent", agents[random.randint(0, len(agents) - 1)])  # 设置请求头
        # try:
        #     sql = self.spidersql.getproxyipspider()
        #     print (sql)
        #     self.cursor.execute(sql)
        #     print ("execute")
        #     data = self.cursor.fetchone()
        #     sql = self.spidersql.updateproxyipusetime(data[0])
        #     self.cursor.execute(sql)
        #     self.mysql.db.commit()
        # except BaseException,e:
        #     self.logger.error(e.message)
        #     self.logger.error("get proxyip sql and update proxyip execute fail,please check ")
        #     self.mysql.db.rollback()
        # else:
        #     proxy = "http://%s:%s" % (str(data[1]).strip(), str(data[2]).strip())
        #     # self.logger.info(proxy)
        #     request.meta['proxy'] = proxy
        #     self.logger.info("get proxyip success: %s port: %s" % (data[1], data[2]))
        return None

    def process_response(self, request, response, spider):
        """
        process_response()应该：返回一个Response 对象，返回一个Request对象或引发IgnoreRequest异常。
        如果它返回Response（可能是相同的给定响应或全新的响应），该响应将继续与process_response()链中的下一个中间件一起处理
        如果它返回一个Request对象，中间件链将被停止，并且返回的请求被重新安排以便日后下载。这与返回请求的行为是一样的process_request()。
        如果引发IgnoreRequest异常，Request.errback则调用request（）的errback函数。如果没有代码处理引发的异常，它将被忽略并且不记录（与其他异常不同）。
        :param request: 
        :param response: 
        :param spider: 
        :return: 
        """
        print("**********process_response12***********")
        print response
        return response

    def process_exception(self, request, exception, spider):
        """
        Scrapy调用process_exception()当下载处理程序或process_request()（从下载中间件）会引发异常（包括IgnoreRequest例外）
        process_exception()应该返回：任一个None，一个Response对象或一个Request对象。
        如果返回None，Scrapy将继续处理此异常，执行任何其他process_exception()安装中间件的方法，直到没有中间件，并且默认的异常处理进入
        如果它返回一个Response对象，process_response() 则启动安装的中间件的方法链，Scrapy不会打扰任何其他process_exception()中间件的方法。
        如果返回一个Request对象，则返回的请求将重新安排，以便将来下载。这样就可以阻止process_exception()中间件的方法的执行 与返回响应一样。
        :param request: 
        :param response: 
        :param spider: 
        :return: 
        """
        print("**********process_exception***********")
        spider.logger.info("IPS page fail %s " % request.meta.get('proxy'))
        sql = spider.spidersql.setbaiducanuse('0', request.meta.get('msqlid'))
        spider.cursor.execute(sql)
        spider.mysql.db.commit()
        return None


class effectivesMiddleware(object):
    def process_request(self, request, spider):
        """
        对于通过下载中间件的每个请求都调用此方法。
        process_request()应该：返回None，返回一个 Response对象，返回一个Request 对象，或者加注IgnoreRequest。
        如果它返回None，Scrapy将继续处理此请求，执行所有其他中间件，直到最后，适当的下载程序处理程序被称为执行的请求（并且其响应已下载）
        如果它返回一个Response对象，Scrapy不会打扰调用任何其他process_request()或process_exception()方法或适当的下载功能; 它会返回该响应。process_response() 安装的中间件的方法总是在每个响应中调用。
        如果它返回一个Request对象，Scrapy将停止调用process_request方法并重新计划返回的请求。一旦执行了新返回的请求，将在下载的响应上调用适当的中间件链。
        如果引发IgnoreRequest异常，process_exception()将会调用安装的下载器中间件的 方法。如果没有处理异常，Request.errback则调用request（）的errback函数。如果没有代码处理引发的异常，它将被忽略并且不记录（与其他异常不同）。
        :param request: 
        :param spider: 
        :return: 
        """
        # # Use the following lines if your proxy requires authentication
        # proxy_user_pass = "USERNAME:PASSWORD"
        # # setup basic authentication for the proxy
        # encoded_user_pass = base64.encodestring(proxy_user_pass)
        # request.headers['Proxy-Authorization'] = 'Basic ' + encoded_user_pass
        print("**********process_request***********")

        return None

    def process_response(self, request, response, spider):
        """
        process_response()应该：返回一个Response 对象，返回一个Request对象或引发IgnoreRequest异常。
        如果它返回Response（可能是相同的给定响应或全新的响应），该响应将继续与process_response()链中的下一个中间件一起处理
        如果它返回一个Request对象，中间件链将被停止，并且返回的请求被重新安排以便日后下载。这与返回请求的行为是一样的process_request()。
        如果引发IgnoreRequest异常，Request.errback则调用request（）的errback函数。如果没有代码处理引发的异常，它将被忽略并且不记录（与其他异常不同）。
        :param request: 
        :param response: 
        :param spider: 
        :return: 
        """
        print("**********process_response***********")
        if request.meta.get('msqlid', None):
            if request.meta.get('mhomepage', None) == 'baidu':
                spider.logger.info("baidu fail %s " % request.meta.get('proxy'))
                sql = spider.spidersql.setbaiducanuse('1', request.meta.get('msqlid'))
                spider.cursor.execute(sql)
                spider.mysql.db.commit()
            if request.meta.get('mhomepage', None) == 'amazon':
                spider.logger.info("amazon fail %s " % request.meta.get('proxy'))
                sql = spider.spidersql.setamazoncanuse('1', request.meta.get('msqlid'))
                spider.cursor.execute(sql)
                spider.mysql.db.commit()
        return response

    def process_exception(self, request, exception, spider):
        """
        Scrapy调用process_exception()当下载处理程序或process_request()（从下载中间件）会引发异常（包括IgnoreRequest例外）
        process_exception()应该返回：任一个None，一个Response对象或一个Request对象。
        如果返回None，Scrapy将继续处理此异常，执行任何其他process_exception()安装中间件的方法，直到没有中间件，并且默认的异常处理进入
        如果它返回一个Response对象，process_response() 则启动安装的中间件的方法链，Scrapy不会打扰任何其他process_exception()中间件的方法。
        如果返回一个Request对象，则返回的请求将重新安排，以便将来下载。这样就可以阻止process_exception()中间件的方法的执行 与返回响应一样。
        :param request: 
        :param response: 
        :param spider: 
        :return: 
        """
        print("**********process_exception***********")
        if request.meta.get('msqlid', None):
            if request.meta.get('mhomepage', None) == 'baidu':
                spider.logger.info("baidu fail %s " % request.meta.get('proxy'))
                sql = spider.spidersql.setbaiducanuse('0', request.meta.get('msqlid'))
                spider.cursor.execute(sql)
                spider.mysql.db.commit()
            if request.meta.get('mhomepage', None) == 'amazon':
                spider.logger.info("amazon fail %s " % request.meta.get('proxy'))
                sql = spider.spidersql.setamazoncanuse('0', request.meta.get('msqlid'))
                spider.cursor.execute(sql)
                spider.mysql.db.commit()

        return None
